package com.yj.auto.plugin.generator;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.sql.DataSource;

import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.dialect.OracleDialect;
import com.jfinal.plugin.activerecord.generator.MetaBuilder;
import com.jfinal.plugin.activerecord.generator.TableMeta;

public class AutoMetaBuilder extends MetaBuilder {
	// 队主键外的，唯一约束字段（只支持单字段）
	public static List<String> UNIQUE_INDEX = new ArrayList<String>();
	// JAVA映射类型
	public static Map<Integer, String> javaType = new HashMap<Integer, String>();
	static {
		javaType.put(Types.TINYINT, "Byte");
		javaType.put(Types.SMALLINT, "Short");
		javaType.put(Types.INTEGER, "Integer");
		javaType.put(Types.BIGINT, "Long");
		javaType.put(Types.REAL, "Float");
		javaType.put(Types.FLOAT, "Double");
		javaType.put(Types.DOUBLE, "Double");
		javaType.put(Types.DECIMAL, "BigDecimal");
		javaType.put(Types.NUMERIC, "BigDecimal");
		javaType.put(Types.BIT, "Boolean");
		javaType.put(Types.BOOLEAN, "Boolean");
		javaType.put(Types.CHAR, "String");
		javaType.put(Types.VARCHAR, "String");
		javaType.put(Types.LONGVARCHAR, "String");
		javaType.put(Types.DATE, "Date");
		javaType.put(Types.TIME, "Date");
		javaType.put(Types.TIMESTAMP, "Date");
		javaType.put(Types.BINARY, "byte[]");
		javaType.put(Types.VARBINARY, "byte[]");
		javaType.put(Types.LONGVARBINARY, "byte[]");
		javaType.put(Types.CLOB, "byte[]");
		javaType.put(Types.BLOB, "byte[]");
	}
	private Set<String> includedTables = new HashSet<String>();

	public AutoMetaBuilder(DataSource dataSource) {
		super(dataSource);
	}

	public List<TableMeta> build(String... tables) {
		includedTables.clear();
		if (null != tables && tables.length > 0) {
			for (String s : tables) {
				includedTables.add(s.toLowerCase());
			}
		}
		return this.build();
	}

	protected void buildTableNames(List<TableMeta> ret) throws SQLException {
		ResultSet rs = getTablesResultSet();
		while (rs.next()) {
			String tableName = rs.getString("TABLE_NAME");
			if (excludedTables.contains(tableName) || isSkipTable(tableName) || (includedTables.size() > 0 && !includedTables.contains(tableName))) {
				// System.out.println("Skip table :" + tableName);
				continue;
			}
			TableMeta tableMeta = new TableMeta();
			tableMeta.name = tableName;
			tableMeta.remarks = rs.getString("REMARKS");
			tableMeta.modelName = buildModelName(tableName);
			tableMeta.baseModelName = buildBaseModelName(tableMeta.modelName);
			ret.add(tableMeta);
		}
		rs.close();
	}

	protected void buildColumnMetas(TableMeta tableMeta) throws SQLException {
		ResultSet rs = getColumnsResultSet(tableMeta.name);
		while (rs.next()) {
			AutoColumnMeta cm = new AutoColumnMeta();
			cm.name = rs.getString("COLUMN_NAME");
			cm.attrName = buildAttrName(cm.name);// 构造字段对应的属性名 attrName
			cm.remarks = rs.getString("REMARKS");
			cm.defaultValue = rs.getString("COLUMN_DEF");
			cm.javaType = getJavaType(rs.getInt("DATA_TYPE"));
			cm.isNullable = rs.getString("IS_NULLABLE"); // 是否允许 NULL 值
			cm.isPrimaryKey = ("," + tableMeta.primaryKey + ",".toLowerCase()).indexOf("," + cm.name + ",".toLowerCase()) < 0 ? null : "true";
			cm.type = rs.getString("TYPE_NAME");
			cm.size = rs.getInt("COLUMN_SIZE"); // 字段长度
			cm.decimal = rs.getInt("DECIMAL_DIGITS"); // 小数位数
			if (!cm.isPK() && UNIQUE_INDEX.contains(cm.name.toLowerCase())) {
				cm.isUnique = true;
			}
			// System.out.println(cm.name+"   "+cm.isNullable);
			tableMeta.columnMetas.add(cm);
		}
		rs.close();
	}

	protected String buildAttrName(String colName) {
		return StrKit.toCamelCase(colName.toLowerCase());
	}

	protected boolean isOracle() {
		return dialect != null && dialect instanceof OracleDialect;
	}

	protected ResultSet getColumnsResultSet(String table) throws SQLException {
		String schemaPattern = null;
		if (isOracle()) {
			schemaPattern = dbMeta.getUserName();
		}
		// 索引
		ResultSet indexRs = null;
		try {
			indexRs = this.conn.getMetaData().getIndexInfo(conn.getCatalog(), schemaPattern, table, true, true);
			while (indexRs.next()) {
				String columnName = indexRs.getString("COLUMN_NAME");
				if (null == columnName)
					continue;
				if (!indexRs.getBoolean("NON_UNIQUE")) {
					UNIQUE_INDEX.add(columnName.toLowerCase());
				}
			}
		} finally {
			if (null != indexRs) {
				indexRs.close();
			}
		}
		// 字段
		ResultSet columnRs = this.conn.getMetaData().getColumns(conn.getCatalog(), schemaPattern, table, null);
		return columnRs;
	}

	protected String getJavaType(int sqlType) {
		String result = javaType.get(sqlType);
		if (result == null) {
			result = "Object";
		}
		return result;
	}

	public static String getModelMethod(String javaType) {
		String method = "get";
		if ("Integer".equals(javaType)) {
			method = "getInt";
		} else if ("Long".equals(javaType)) {
			method = "getLong";
		} else if ("Float".equals(javaType)) {
			method = "getFloat";
		} else if ("Double".equals(javaType)) {
			method = "getDouble";
		} else if ("Boolean".equals(javaType)) {
			method = "getBoolean";
		} else if ("String".equals(javaType)) {
			method = "getStr";
		} else if ("Date".equals(javaType)) {
			method = "getDate";
		} else if ("byte[]".equals(javaType)) {
			method = "getBytes";
		}
		return method;
	}
}
